/*
 * This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so
 * anyone can use the definitions to implement compatible drivers/servers:
 *
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of IBM nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * Copyright (C) Inochi Amaoto <amaoto-inochi@outlook.com>
 */

#ifndef _LINUX_VIRTIO_VAPP_H
#define _LINUX_VIRTIO_VAPP_H

#include <linux/types.h>
#include <linux/ioctl.h>
#include <linux/virtio_types.h>
#include <linux/virtio_ids.h>
#include <linux/virtio_config.h>
#include <linux/const.h>

#ifndef __KERNEL__
# ifndef __user
# define __user
# endif
#endif

/* virtio virtual application */
#define VIRTIO_ID_VAPP                    60
#define PCI_DEVICE_ID_VIRTIO_VAPP         0x107c

/**
 * Userspace ioctl command should start from 0x00
 * Backend ioctl command should start from 0x80
 * Frontend ioctl command should start from 0xa0
 */
enum {
  __VIRTIO_VAPP_CTRL_REQ = 0x07,
  __VIRTIO_VAPP_CTRL_RSP = 0x17,

  __VIRTIO_VAPP_OPEN_REQ = 0x08,
  __VIRTIO_VAPP_CLOSE_REQ = 0x18,
  __VIRTIO_VAPP_OPEN_RSP = 0x09,
  __VIRTIO_VAPP_CLOSE_RSP = 0x19,

  __VIRTIO_VAPP_SET_UUID = 0x81,
  __VIRTIO_VAPP_SET_RUNNING = 0x82,
  __VIRTIO_VAPP_RESET = 0x83,
  __VIRTIO_VAPP_SET_MULTIQUEUES = 0x84,
};

#define VIO_VAPP_NR_DATA_DTQS_MAX  4
#define VIO_VAPP_NR_CTRL_DTQS_MAX  1

#define VIO_VAPP_IOC_MAGIC      0x9A

#define VIO_VAPP_IO_CTRL_REQ _IOWR(VIO_VAPP_IOC_MAGIC, __VIRTIO_VAPP_CTRL_REQ, struct vio_vapp_ctrl_req*)
#define VIO_VAPP_IO_CTRL_RSP _IOWR(VIO_VAPP_IOC_MAGIC, __VIRTIO_VAPP_CTRL_RSP, struct vio_vapp_ctrl_rsp*)

#define VIO_VAPP_IO_OPEN_REQ _IOWR(VIO_VAPP_IOC_MAGIC, __VIRTIO_VAPP_OPEN_REQ, struct vio_vapp_request*)
#define VIO_VAPP_IO_CLOSE_REQ _IOWR(VIO_VAPP_IOC_MAGIC, __VIRTIO_VAPP_CLOSE_REQ, struct vio_vapp_request*)
#define VIO_VAPP_IO_OPEN_RSP _IOWR(VIO_VAPP_IOC_MAGIC, __VIRTIO_VAPP_OPEN_RSP, void*)
#define VIO_VAPP_IO_CLOSE_RSP _IOWR(VIO_VAPP_IOC_MAGIC, __VIRTIO_VAPP_CLOSE_RSP, void*)

#define VHOST_VAPP_IO_SET_UUID _IOW(VIO_VAPP_IOC_MAGIC, __VIRTIO_VAPP_SET_UUID, uint64_t*)
#define VHOST_VAPP_IO_SET_MULTIQUEUES _IOW(VIO_VAPP_IOC_MAGIC, __VIRTIO_VAPP_SET_MULTIQUEUES, uint64_t*)
#define VHOST_VAPP_IO_SET_RUNNING _IOW(VIO_VAPP_IOC_MAGIC, __VIRTIO_VAPP_SET_RUNNING, uint64_t*)
#define VHOST_VAPP_IO_RESET _IO(VIO_VAPP_IOC_MAGIC, __VIRTIO_VAPP_RESET)

#define VHOST_VAPP_DEVICE_NAME "vhost-vapp"
#define VIRTIO_VAPP_DEVICE_NAME "virtio-vapp"
#define VAPP_USER_DEVICE_NAME "vio-app"

#define VIO_VAPP_PKT_SHIFT  16
#define VIO_VAPP_PKT_SIZE   (_AC(1,UL) << VIO_VAPP_PKT_SHIFT)
#define VIO_VAPP_PKT_MASK   (~(VIO_VAPP_PKT_SIZE - 1))

#define VIO_VAPP_QUEUE_NR_PKT   128

#define VIO_VAPP_ENTITY_PKTS   64
#define VIO_VAPP_ENTITY_SIZE   (VIO_VAPP_PKT_SIZE * VIO_VAPP_ENTITY_PKTS)
#define VIO_VAPP_ENTITY_SHIFT  (6 + VIO_VAPP_PKT_SHIFT)

#define VIO_VAPP_MAX_MMAP   64

#define VIO_VAPP_PKT_PAGES (VIO_VAPP_PKT_SIZE / PAGE_SIZE)
#define VIO_VAPP_ENTITY_PAGES (VIO_VAPP_ENTITY_SIZE / PAGE_SIZE)

struct virtio_vapp_config {
  __le64 multiqueues;
  __le64 uuid;
};

struct virtio_vapp_cpu_config {
  uint64_t multiqueues;
  uint64_t uuid;
};

struct vio_vapp_ctrl_req {
  uint32_t      op;
  uint32_t      feature;
  uint8_t       id;
  uint8_t       data[48];
};

struct vio_vapp_ctrl_rsp {
  uint8_t       id;
  uint32_t      status;
};

struct vio_vapp_request {
  uint64_t      id;
#ifdef VHOST_VAPP
  uint64_t      uuid;
  uint64_t      fp;
#endif
  uint64_t      count;
  uint32_t      type;
  void* __user  addr;
};

struct vio_vapp_respond {
  uint64_t      id;
#ifdef VHOST_VAPP
  uint64_t      uuid;
#endif
  uint64_t      count;
  uint32_t      type;
  void* __user  addr;
};

/**
 * ctrl data shared with host and reqest
 */
struct vio_ctrl_request {
  uint32_t      op;
  uint16_t      feature;
  uint16_t      id;
  uint8_t       data[48];
};

/**
 * All the VQ from dts is a pair.
 * The id of vqs are defined as follows.
 */
enum {
  /* host -> guest */
  __VAPP_VQ_RX = 0,
  /* guest -> host */
  __VAPP_VQ_TX = 1,
  /*  */
  __VAPP_VQ_MAX
};

/**
 * req/rsp type feature bits
 */
enum {
  VIO_TYPE_GUEST = 0,
  VIO_NOREPLY_BIT = 1,
};

#define VIO_TYPE_GUEST        (1 << (VIO_TYPE_GUEST))
#define VIO_TYPE_NOREPLY      (1 << (VIO_NOREPLY_BIT))

#define __VIO_TYPE_HOST       (0 << (VIO_TYPE_GUEST))

#define VIO_TYPE_GET_GUEST_BIT(_type)    ((_type) & VIO_TYPE_GUEST)
#define VIO_TYPE_CLEAR_GUEST_BIT(_type)  ((_type) & (~VIO_TYPE_GUEST))
#define VIO_TYPE_IS_NOREPLY(_type)  ((_type) & VIO_TYPE_NOREPLY)
#define VIO_TYPE_IS_HOST(_type)  (((_type) & VIO_TYPE_GUEST) == 0)
#define VIO_TYPE_IS_GUEST(_type)  (((_type) & VIO_TYPE_GUEST))


#endif // ! _LINUX_VIRTIO_VAPP_H
